/*
 * 版权所有 (c) 华为技术有限公司 2022-2022
 */
package com.huawei.cameratest;

import android.Manifest;
import android.app.Activity;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Rect;
import android.hardware.Camera;
import android.hardware.camera2.*;
import android.media.ImageReader;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import android.provider.Settings;
import android.support.annotation.NonNull;
import android.support.v4.content.ContextCompat;
import android.util.Log;
import android.util.Range;
import android.util.Size;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;

import com.huawei.cameratest.data.CaptureRequestEx;
import com.huawei.cameratest.data.ImageFormatEx;
import com.huawei.cameratest.data.StreamConfig;
import com.huawei.cameratest.data.StreamView;
import com.huawei.cameratest.util.MultiStreamTagUtil;
import com.huawei.cameratest.util.StreamConfigDB;

import java.io.File;
import java.io.FileDescriptor;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

import static android.view.View.GONE;
import static android.view.View.VISIBLE;
import static com.huawei.cameratest.MultiImageReaderSettingActivity.*;
import static com.huawei.cameratest.util.MultiStreamTagUtil.*;

import static com.huawei.cameratest.MyApplication.saveRect;
import static com.huawei.cameratest.MyApplication.startTime;

public class MultiImageReaderActivity extends Activity {
    // 每路流的详细配置数据
    public static List<StreamConfig> streamConfigs = new ArrayList<>();
    public static long time;

    public static boolean isRunning = false;
    public static boolean isLocalStore = true;
    public static boolean isDisplayStream = false;
    public static boolean isResolveLocalVideo = false;

    private final String TAG = this.getClass().getSimpleName();

    private SurfaceView previewSurface;

    // resolve local video
    private SurfaceView localVideoView1;
    private SurfaceView localVideoView2;
    private SurfaceView localVideoView3;
    private SurfaceView localVideoView4;

    private SurfaceView surfaceView1;
    private SurfaceHolder surfaceHolder1;
    private SurfaceView surfaceView2;
    private SurfaceHolder surfaceHolder2;

    private CameraManager mCameraManager;
    private CameraDevice mCameraDevice;
    private CameraCaptureSession mCaptureSession;
    private CaptureRequest.Builder mPreviewRequestBuilder;
    private SurfaceHolder mSurfaceHolder;
    private HandlerThread mBackgroundThread;
    private Handler mBackgroundHandler;
    private Handler fpsHanlder;

    private String mCameraId;
    private String previewResolution;
    private String fpsString;
    private boolean isPreview;
    private int streamNumber;
    private int reCfgFlag = -1;

    private File mFile0;
    private File mFile1;
    private File mFile2;
    private File mFile3;

    StreamView[] dynamicStreamViews;

    private Spinner dynamic0Resolution;
    private Spinner dynamic0EncodeBitrate;
    private Spinner dynamic0QualityParamMin;
    private Spinner dynamic0QualityParamMax;
    private Spinner dynamic0RequestIFrame;
    private Spinner dynamic0Protocol;
    private Spinner dynamic0Fps;

    private Spinner dynamic1Resolution;
    private Spinner dynamic1EncodeBitrate;
    private Spinner dynamic1QualityParamMin;
    private Spinner dynamic1QualityParamMax;
    private Spinner dynamic1RequestIFrame;
    private Spinner dynamic1Protocol;
    private Spinner dynamic1Fps;

    private Spinner dynamic2Resolution;
    private Spinner dynamic2EncodeBitrate;
    private Spinner dynamic2QualityParamMin;
    private Spinner dynamic2QualityParamMax;
    private Spinner dynamic2RequestIFrame;
    private Spinner dynamic2Protocol;
    private Spinner dynamic2Fps;

    private Spinner dynamic3Resolution;
    private Spinner dynamic3EncodeBitrate;
    private Spinner dynamic3QualityParamMin;
    private Spinner dynamic3QualityParamMax;
    private Spinner dynamic3RequestIFrame;
    private Spinner dynamic3Protocol;
    private Spinner dynamic3Fps;

    private Button changeButton;
    private Button previewButton;
    private Button stream0Button;
    private Button stream1Button;
    private Button stream2Button;
    private Button stream3Button;
    private Button ptzTestButton;
    private Button tagTestButton;
    private ImageReader[] imageReaders;
    private File[] files;
    private MyImageReader[] myImageReaders;
    private TextView fpsTextView0;
    private TextView fpsTextView1;
    private TextView fpsTextView2;
    private TextView fpsTextView3;
    private final TextView[] fpsTextViews = {fpsTextView0, fpsTextView1, fpsTextView2, fpsTextView3};
    private List<Surface> outputSurfaceList;

    private String decodeVideoPath = Environment.getExternalStorageDirectory() + File.separator +
            "CameraResources" + File.separator;

    // 解码透传流
    private DecodeInputThread decodeInputThread1;
    private DecodeInputThread decodeInputThread2;

    // 存储透传流
    private StoreFileThread storeFileThread1;
    private StoreFileThread storeFileThread2;
    private StoreFileThread storeFileThread3;
    private StoreFileThread storeFileThread4;

    boolean previewRemoveFlag = true;
    boolean stream0RemoveFlag = true;
    boolean stream1RemoveFlag = true;
    boolean stream2RemoveFlag = true;
    boolean stream3RemoveFlag = true;

    CameraCaptureSession.CaptureCallback mCaptureCallback = new CameraCaptureSession.CaptureCallback() {
        @Override
        public void onCaptureCompleted(CameraCaptureSession session,
                                       CaptureRequest request,
                                       TotalCaptureResult result) {
            super.onCaptureCompleted(session, request, result);
        }

        @Override
        public void onCaptureFailed(CameraCaptureSession session, CaptureRequest request, CaptureFailure failure) {
            Log.i(TAG, "Enter onCaptureFailed: " + failure.getReason());
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_multi_image_reader);
        Intent intent = getIntent();
        mCameraId = intent.getStringExtra(ID);
        previewResolution = intent.getStringExtra(RESOLUTION);
        fpsString = intent.getStringExtra(SET_FPS);
        isPreview = "true".equals(intent.getStringExtra(PREVIEW));
        streamNumber = Integer.valueOf(intent.getStringExtra(STREAM_NUMBER));
        streamConfigs = StreamConfigDB.getInstance().getStreamConfigs();
        Log.i(TAG, "stream config numbers" + streamConfigs.size() + "stream number" + streamNumber);
    }

    @Override
    protected void onResume() {
        initData();
        initView();

        LinearLayout fpsLinearLayout0 = findViewById(R.id.linear_passthrough_stream0_fps);
        LinearLayout fpsLinearLayout1 = findViewById(R.id.linear_passthrough_stream1_fps);
        LinearLayout fpsLinearLayout2 = findViewById(R.id.linear_passthrough_stream2_fps);
        LinearLayout fpsLinearLayout3 = findViewById(R.id.linear_passthrough_stream3_fps);
        LinearLayout[] fpsLinearLayouts = {fpsLinearLayout0, fpsLinearLayout1, fpsLinearLayout2, fpsLinearLayout3};

        for (int i = streamNumber; i < 4; i++) {
            fpsLinearLayouts[i].setVisibility(GONE);
        }

        fpsTextView0 = findViewById(R.id.text_passthrough_stream0_fps);
        fpsTextView1 = findViewById(R.id.text_passthrough_stream1_fps);
        fpsTextView2 = findViewById(R.id.text_passthrough_stream2_fps);
        fpsTextView3 = findViewById(R.id.text_passthrough_stream3_fps);

        fpsHanlder = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                switch (msg.arg1) {
                    case 0:fpsTextView0.setText((String)msg.obj); break;
                    case 1:fpsTextView1.setText((String)msg.obj); break;
                    case 2:fpsTextView2.setText((String)msg.obj); break;
                    case 3:fpsTextView3.setText((String)msg.obj); break;
                    default:
                        throw new IllegalStateException("Unexpected value: " + msg.arg1);
                }
//                if (msg.arg1 == 0) {
//                    fpsTextView0.setText((String)msg.obj);
//                } else {
//                    fpsTextView1.setText((String)msg.obj);
//                }
            }
        };

        new MyThread().start();


//        new Timer().schedule(new TimerTask() {
//            @Override
//            public void run() {
//                TextView fpsTextView = findViewById(R.id.text_passthrough_stream0_fps);
//                fpsTextView.setText("" + myImageReaders[0].getFps());
//            }
//        }, 0, 1000);
        super.onResume();
        startBackgroundThread();
    }

    class MyThread extends Thread {
        @Override
        public void run() {
            while(true) {
                for (int i = 0; i < streamNumber; i++) {
                    Message streamFpsMessage = Message.obtain(fpsHanlder);
                    streamFpsMessage.arg1 = i;
                    streamFpsMessage.obj = "" + myImageReaders[i].getFps();
                    fpsHanlder.sendMessage(streamFpsMessage);
                }
//                Message stream_0_fpsMessage = Message.obtain(fpsHanlder);
//                stream_0_fpsMessage.arg1 = 0;
//                stream_0_fpsMessage.obj = "" + myImageReaders[0].getFps();
//                fpsHanlder.sendMessage(stream_0_fpsMessage);
//
//                if (streamNumber != 1) {
//                    Message stream_1_fpsMessage = Message.obtain(fpsHanlder);
//                    stream_1_fpsMessage.arg1 = 1;
//                    stream_1_fpsMessage.obj = "" + myImageReaders[1].getFps();
//                    fpsHanlder.sendMessage(stream_1_fpsMessage);
//                }

                try {
                    Thread.sleep(1000);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private void initData() {
        checkInputFile();
        isRunning = true;
        imageReaders = new ImageReader[streamNumber];
        files = new File[]{mFile0, mFile1, mFile2, mFile3};
        myImageReaders = new MyImageReader[streamConfigs.size()];
        for (int i = 0; i < streamNumber; i++) {
            Size size = toSize(streamConfigs.get(i).getResolution());
            String format = streamConfigs.get(i).getFormat();
            if (format.equals("H264")) {
                myImageReaders[i] = new MyImageReader(size, ImageFormatEx.H264, files[i], i);
//                myImageReaders[i] = new MyImageReader(size, ImageFormatEx.H264, files[i], i, this);
            } else {
                myImageReaders[i] = new MyImageReader(size, ImageFormatEx.H265, files[i], i);
//                myImageReaders[i] = new MyImageReader(size, ImageFormatEx.H265, files[i], i, this);
            }
//            imageReaders[i] = myImageReaders[i].run();
            imageReaders[i] = myImageReaders[i].run();
            Log.d(TAG, "openCamera: CreateImageReader" + i);
        }
    }

    private void initView() {
        previewSurface = findViewById(R.id.previewSurface0);
        Size size = toSize(previewResolution);
        mSurfaceHolder = previewSurface.getHolder();
        mSurfaceHolder.setFixedSize(size.getWidth(), size.getHeight());
        mSurfaceHolder.addCallback(new SurfaceHolder.Callback() {
            @Override
            public void surfaceCreated(SurfaceHolder holder) {
                openCamera(mCameraId);
            }

            @Override
            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
            }

            @Override
            public void surfaceDestroyed(SurfaceHolder holder) {
                Log.i(TAG, "surfaceDestroyed: ");
                mSurfaceHolder = holder;
                mSurfaceHolder.removeCallback(this);
            }
        });
        Log.i(TAG, "steamNumber " + streamNumber);
        initStreamDisplayView();

        initDynamicView(streamNumber);
//        TextView stream0 = findViewById(R.id.text_passthrough_stream0_fps);
//        stream0.setText("1000");
//        TextView stream1 = findViewById(R.id.text_passthrough_stream1_fps);
//        stream1.setText("1000");
    }

    private void initStreamDisplayView() {
        LinearLayout localVideoLayout = findViewById(R.id.localVideo);
        LinearLayout streamDisplayLayout = findViewById(R.id.streamDisplay);
        if (streamNumber > 0) {
            if (isLocalStore) {
                streamDisplayLayout.setVisibility(GONE);
                localVideoLayout.setVisibility(GONE);
                storeStream();
            } else if (isResolveLocalVideo) {
                streamDisplayLayout.setVisibility(GONE);
                localVideoLayout.setVisibility(VISIBLE);
                storeStream();
                resolveLocalVideo();
            } else if (isDisplayStream) {
                streamDisplayLayout.setVisibility(VISIBLE);
                localVideoLayout.setVisibility(GONE);
                surfaceView1 = findViewById(R.id.surfaceView1);
                surfaceHolder1 = surfaceView1.getHolder();
                Size size1 = toSize(streamConfigs.get(0).getResolution());
                surfaceHolder1.setFixedSize(size1.getWidth(), size1.getHeight());
                surfaceHolder1.addCallback(callback1);
                if (streamNumber == 2) {
                    surfaceView2 = findViewById(R.id.surfaceView2);
                    surfaceHolder2 = surfaceView2.getHolder();
                    Size size2 = toSize(streamConfigs.get(1).getResolution());
                    surfaceHolder2.setFixedSize(size2.getWidth(), size2.getHeight());
                    surfaceHolder2.addCallback(callback2);
                }
            }
        } else {
            streamDisplayLayout.setVisibility(GONE);
            localVideoLayout.setVisibility(GONE);
        }
    }

    public void resolveLocalVideo() {
        Log.i(TAG, "begin resolve local video");
        localVideoView1 = findViewById(R.id.surface1);
        localVideoView2 = findViewById(R.id.surface2);
        localVideoView3 = findViewById(R.id.surface3);
        localVideoView4 = findViewById(R.id.surface4);
        List<SurfaceView> viewList = Arrays.asList(localVideoView1, localVideoView2, localVideoView3, localVideoView4);
        for (int i = 0; i < viewList.size(); i++) {
            resolveLocalVideo(viewList.get(i), decodeVideoPath + "localvideo" + i + ".mp4");
        }
    }

    public void storeStream() {
        StoreFileThread[] storeFileThreads = new StoreFileThread[]{storeFileThread1, storeFileThread2, storeFileThread3, storeFileThread4};
        for (int i = 0; i < streamConfigs.size(); i++) {
            if (storeFileThreads[i] == null) {
                storeFileThreads[i] = new StoreFileThread(files[i], myImageReaders[i].getH264BufferQueue());
                storeFileThreads[i].start();
            }
        }
    }

    private void resolveLocalVideo(SurfaceView surfaceView, String path) {
        Log.i(TAG, "resolve local video " + path);
        DecodeVideoThread decodeVideoThread = new DecodeVideoThread(surfaceView.getHolder().getSurface(), path);
        surfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {
            @Override
            public void surfaceCreated(@NonNull SurfaceHolder holder) {
                decodeVideoThread.start();
            }

            @Override
            public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) {
            }

            @Override
            public void surfaceDestroyed(@NonNull SurfaceHolder holder) {
                if (decodeVideoThread != null) {
                    decodeVideoThread.interrupt();
                }
            }
        });
    }

    private void checkInputFile() {
        mFile0 = new File(Environment.getExternalStorageDirectory() + File.separator +
                "CameraResources" + File.separator, "video0.mp4");
        mFile1 = new File(Environment.getExternalStorageDirectory() + File.separator +
                "CameraResources" + File.separator, "video1.mp4");
        mFile2 = new File(Environment.getExternalStorageDirectory() + File.separator +
                "CameraResources" + File.separator, "video2.mp4");
        mFile3 = new File(Environment.getExternalStorageDirectory() + File.separator +
                "CameraResources" + File.separator, "video3.mp4");
        File dir = new File(Environment.getExternalStorageDirectory() + File.separator +
                "CameraResources" + File.separator);
        if (dir.exists()) {
            if (mFile0.exists()) {
                if (!mFile0.delete()) {
                    Log.e(TAG, "delete file failure.");
                }
            }
            if (mFile1.exists()) {
                if (!mFile1.delete()) {
                    Log.e(TAG, "delete file failure.");
                }
            }
            if (mFile2.exists()) {
                if (!mFile2.delete()) {
                    Log.e(TAG, "delete file failure.");
                }
            }
            if (mFile2.exists()) {
                if (!mFile2.delete()) {
                    Log.e(TAG, "delete file failure.");
                }
            }
        } else {
            if (!dir.mkdir()) {
                Log.e(TAG, "mkdir failure.");
            }
            Log.i(TAG, "create dir CameraResources");
        }
    }


    private void openCamera(String mCameraID) {
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
                != PackageManager.PERMISSION_GRANTED) {
            Log.e(TAG, "no camera access permission");
            return;
        }
        mCameraManager = (CameraManager) this.getSystemService(Context.CAMERA_SERVICE);
        time = new Date().getTime();
        try {
            mCameraManager.openCamera(mCameraID, mStateCallback, mBackgroundHandler);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

    CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {
        @Override
        public void onOpened(CameraDevice cameraDevice) {
            mCameraDevice = cameraDevice;
            Log.i(TAG, "createCameraPreviewSession");
            createCameraPreviewSession();
        }

        @Override
        public void onDisconnected(CameraDevice cameraDevice) {
            cameraDevice.close();
            mCameraDevice = null;
            Log.e(TAG, "Camera device disconnected");
            Activity activity = MultiImageReaderActivity.this;
            if (null != activity) {
                activity.finish();
            }
        }

        @Override
        public void onError(CameraDevice cameraDevice, int error) {
            Log.e(TAG, "Camera Error :" + error);
            cameraDevice.close();
            mCameraDevice = null;
            Activity activity = MultiImageReaderActivity.this;
            if (null != activity) {
                activity.finish();
            }
        }
    };

    private void createCameraPreviewSession() {
        try {
            mPreviewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW + 0x40000000);
//            mPreviewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);

//            mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, toRange(fpsString));
            if (startTime == 0) {
                mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, new Range<>(30,30));
                startTime++;
            } else {
                mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, new Range<>(24,24));
            }
            setExTagValuesForRequestBuilder();
            outputSurfaceList = new ArrayList<>();

            for (int i = 0; i < streamNumber; i++) {
                mPreviewRequestBuilder.addTarget(imageReaders[i].getSurface());
                outputSurfaceList.add(imageReaders[i].getSurface());
                Log.d(TAG, "createCameraPreviewSession: outputs add imageReader" + i);
            }
            if (isPreview) {
                Log.d(TAG, "createCameraPreviewSession: size" + previewResolution);
                mPreviewRequestBuilder.addTarget(mSurfaceHolder.getSurface());
                outputSurfaceList.add(mSurfaceHolder.getSurface());
            }
            mCameraDevice.createCaptureSession(outputSurfaceList, mCaptureStateCallback, mBackgroundHandler);

//            Rect cropRegion3 = new Rect(945, 531, 1949, 1096);
            if (saveRect != null) {
                mPreviewRequestBuilder.set(CaptureRequest.SCALER_CROP_REGION, saveRect); // 设置ptz参数
            }
        } catch (CameraAccessException e) {
            Log.e(TAG, "create Camera Preview Session error!");
            e.printStackTrace();
        }
    }

    private void setExTagValuesForRequestBuilder() {
        if (!streamConfigs.isEmpty()) {
            setExTag(CaptureRequestEx.VIDEO_AUTO_ENCODEBITRATE, MultiStreamTagUtil.constructIntTags(streamConfigs, "getEncodeBitrate"));
            setExTag(CaptureRequestEx.VIDEO_AUTO_IFRAMEINTERVAL, MultiStreamTagUtil.constructIntTags(streamConfigs, "getIframeInterval"));
            setExTag(CaptureRequestEx.H264_SVC, MultiStreamTagUtil.constructIntTags(streamConfigs, "getSvcMode"));
            // for bitMode test
//            final Integer[] bigModeTest = {4, 0, 3, 1, 3, 2, 3, 3, 3};
//            setExTag(CaptureRequestEx.VIDEO_AUTO_BITRATE_MODE, bigModeTest);
        }
    }

    private void setExTag(CaptureRequest.Key key, Object value) {
        if (value != null) {
            Log.i(TAG, "setExTAG " + key.getName());
            mPreviewRequestBuilder.set(key, value);
        }
    }

    CameraCaptureSession.StateCallback mCaptureStateCallback = new CameraCaptureSession.StateCallback() {
        @Override
        public void onConfigured(CameraCaptureSession session) {
            if (mCameraDevice == null) {
                return;
            }
            mCaptureSession = session;
            try {
                mCaptureSession.setRepeatingRequest(mPreviewRequestBuilder.build(), mCaptureCallback, mBackgroundHandler);
            } catch (CameraAccessException e) {
                Log.e(TAG, "onConfigured: setRepeatingRequest error!");
                e.printStackTrace();
            }
        }

        @Override
        public void onConfigureFailed(CameraCaptureSession session) {
        }
    };

    private void startBackgroundThread() {
        mBackgroundThread = new HandlerThread("CameraBackground");
        mBackgroundThread.start();
        mBackgroundHandler = new Handler(mBackgroundThread.getLooper());
    }

    private void stopBackgroundThread() {
        mBackgroundThread.quitSafely();
        try {
            mBackgroundThread.join();
            mBackgroundThread = null;
            mBackgroundHandler = null;
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        for (int i = 0; i < streamNumber; i++) {
            myImageReaders[i].close();
        }
    }

    @Override
    protected void onDestroy() {
        for (int i = 0; i < streamConfigs.size(); i++) {
            Log.i(TAG, "count" + myImageReaders[i].getCount());
        }
        closeCamera();
        stopBackgroundThread();
        super.onDestroy();
    }

    private void closeCamera() {
        isRunning = false;
        if (null != mCaptureSession) {
            mCaptureSession.close();
            mCaptureSession = null;
        }
        if (null != mCameraDevice) {
            mCameraDevice.close();
            mCameraDevice = null;
        }
        for (int i = 0; i < streamNumber; i++) {
            if (null != imageReaders[i]) {
                Log.d(TAG, "close: imageReader" + i + " close");
                imageReaders[i].close();
                imageReaders[i] = null;
            }
        }
        if (storeFileThread4 != null) {
            storeFileThread4.interrupt();
        }
        if (storeFileThread3 != null) {
            storeFileThread3.interrupt();
        }
        if (storeFileThread2 != null) {
            storeFileThread2.interrupt();
        }
        if (storeFileThread1 != null) {
            storeFileThread1.interrupt();
        }
    }

    private void initDynamicView(int number) {
        changeButton = findViewById(R.id.btnStreamChange);
        previewButton = findViewById(R.id.previewChange);
        stream0Button = findViewById(R.id.stream0Change);
        stream1Button = findViewById(R.id.stream1Change);
        stream2Button = findViewById(R.id.stream2Change);
        stream3Button = findViewById(R.id.stream3Change);
        ptzTestButton = findViewById(R.id.ptzTest);
        tagTestButton = findViewById(R.id.tagTest);

//        if (number < 2) {
//            streamNumber = number;
//        } else {
//            streamNumber = 2;
//        }
//
        if (streamNumber > 0) {
            changeButton.setOnClickListener(btnStartClick);
        } else {
            changeButton.setVisibility(GONE);
            stream0Button.setVisibility(GONE);
            stream1Button.setVisibility(GONE);
            stream2Button.setVisibility(GONE);
            stream3Button.setVisibility(GONE);
        }
        if (!isPreview) {
            previewButton.setVisibility(GONE);
        }
        previewButton.setOnClickListener(previewClick);
        stream0Button.setOnClickListener(stream0Click);
        stream1Button.setOnClickListener(stream1Click);
        stream2Button.setOnClickListener(stream2Click);
        stream3Button.setOnClickListener(stream3Click);
        ptzTestButton.setOnClickListener(ptzTestClick);
        tagTestButton.setOnClickListener(tagTestClick);

        LinearLayout linearLayoutForStream0 = findViewById(R.id.linear_dynamic0_id);
        LinearLayout linearLayoutForStream1 = findViewById(R.id.linear_dynamic1_id);
        LinearLayout linearLayoutForStream2 = findViewById(R.id.linear_dynamic2_id);
        LinearLayout linearLayoutForStream3 = findViewById(R.id.linear_dynamic3_id);
        LinearLayout[] linearLayouts = new LinearLayout[]{linearLayoutForStream0, linearLayoutForStream1, linearLayoutForStream2, linearLayoutForStream3};
        for (int i = 0; i < linearLayouts.length; i++) {
            linearLayouts[i].setVisibility(GONE);
        }
        dynamic0Resolution      = findViewById(R.id.Spinner_dynamic0_resolution_id);
        dynamic0EncodeBitrate   = findViewById(R.id.Spinner_dynamic0_encodeBitrate_id);
        dynamic0QualityParamMin = findViewById(R.id.Spinner_dynamic0_qualityParam1_id);
        dynamic0QualityParamMax = findViewById(R.id.Spinner_dynamic0_qualityParam2_id);
        dynamic0RequestIFrame   = findViewById(R.id.Spinner_dynamic0_requestIFrame_id);
        dynamic0Protocol        = findViewById(R.id.Spinner_dynamic0_protocol_id);
        dynamic0Fps             = findViewById(R.id.Spinner_dynamic0_fps_id);

        dynamic1Resolution      = findViewById(R.id.Spinner_dynamic1_resolution_id);
        dynamic1EncodeBitrate   = findViewById(R.id.Spinner_dynamic1_encodeBitrate_id);
        dynamic1QualityParamMin = findViewById(R.id.Spinner_dynamic1_qualityParam1_id);
        dynamic1QualityParamMax = findViewById(R.id.Spinner_dynamic1_qualityParam2_id);
        dynamic1RequestIFrame   = findViewById(R.id.Spinner_dynamic1_requestIFrame_id);
        dynamic1Protocol        = findViewById(R.id.Spinner_dynamic1_protocol_id);
        dynamic1Fps             = findViewById(R.id.Spinner_dynamic1_fps_id);

        dynamic2Resolution      = findViewById(R.id.Spinner_dynamic2_resolution_id);
        dynamic2EncodeBitrate   = findViewById(R.id.Spinner_dynamic2_encodeBitrate_id);
        dynamic2QualityParamMin = findViewById(R.id.Spinner_dynamic2_qualityParam1_id);
        dynamic2QualityParamMax = findViewById(R.id.Spinner_dynamic2_qualityParam2_id);
        dynamic2RequestIFrame   = findViewById(R.id.Spinner_dynamic2_requestIFrame_id);
        dynamic2Protocol        = findViewById(R.id.Spinner_dynamic2_protocol_id);
        dynamic2Fps             = findViewById(R.id.Spinner_dynamic2_fps_id);

        dynamic3Resolution      = findViewById(R.id.Spinner_dynamic3_resolution_id);
        dynamic3EncodeBitrate   = findViewById(R.id.Spinner_dynamic3_encodeBitrate_id);
        dynamic3QualityParamMin = findViewById(R.id.Spinner_dynamic3_qualityParam1_id);
        dynamic3QualityParamMax = findViewById(R.id.Spinner_dynamic3_qualityParam2_id);
        dynamic3RequestIFrame   = findViewById(R.id.Spinner_dynamic3_requestIFrame_id);
        dynamic3Protocol        = findViewById(R.id.Spinner_dynamic3_protocol_id);
        dynamic3Fps             = findViewById(R.id.Spinner_dynamic3_fps_id);

        StreamView streamView0 = new StreamView(dynamic0Resolution, dynamic0EncodeBitrate, dynamic0QualityParamMin, dynamic0QualityParamMax,
                dynamic0RequestIFrame, dynamic0Protocol, dynamic0Fps, MultiImageReaderActivity.this);
        StreamView streamView1 = new StreamView(dynamic1Resolution, dynamic1EncodeBitrate, dynamic1QualityParamMin, dynamic1QualityParamMax,
                dynamic1RequestIFrame, dynamic1Protocol, dynamic1Fps, MultiImageReaderActivity.this);
        StreamView streamView2 = new StreamView(dynamic2Resolution, dynamic2EncodeBitrate, dynamic2QualityParamMin, dynamic2QualityParamMax,
                dynamic2RequestIFrame, dynamic2Protocol, dynamic2Fps, MultiImageReaderActivity.this);
        StreamView streamView3 = new StreamView(dynamic3Resolution, dynamic3EncodeBitrate, dynamic3QualityParamMin, dynamic3QualityParamMax,
                dynamic3RequestIFrame, dynamic3Protocol, dynamic3Fps, MultiImageReaderActivity.this);
        dynamicStreamViews = new StreamView[]{streamView0, streamView1, streamView2, streamView3};
        for (int i = 0; i < streamNumber; i++) {
            linearLayouts[i].setVisibility(VISIBLE);
            StreamView dynamicStreamView = dynamicStreamViews[i];
            StreamConfig streamConfig = streamConfigs.get(i);
//            dynamicStreamView.initResolutionWithDefaultValue(resolutions, streamConfig.getResolution());
            dynamicStreamView.initResolutionWithDefaultValue(streamConfig.getResolution());
            dynamicStreamView.initEncodeBitrateWithDefaultValue(String.valueOf(streamConfig.getEncodeBitrate()));
            dynamicStreamView.initQualityParamWithDefaultValue(String.valueOf(streamConfig.getQpMin()), String.valueOf(streamConfig.getQpMax()));
            dynamicStreamView.initRequestIFrameWithDefaultValue(String.valueOf(streamConfig.getRequestIFrame()));
            dynamicStreamView.initProtocol();
            dynamicStreamView.initFps();
        }
    }

    SurfaceHolder.Callback callback1 = new SurfaceHolder.Callback() {
        @Override
        public void surfaceCreated(SurfaceHolder holder) {
        }

        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
            Log.d(TAG, "surfaceChanged1: ");
            consumeStream(decodeInputThread1, 0, holder);
        }

        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {
            Log.d(TAG, "surfaceDestroyed: surface1");
            if (decodeInputThread1 != null) {
                decodeInputThread1.interrupt();
            }
        }
    };

    SurfaceHolder.Callback callback2 = new SurfaceHolder.Callback() {
        @Override
        public void surfaceCreated(SurfaceHolder holder) {
        }

        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
            Log.d(TAG, "surfaceChanged2: ");
            consumeStream(decodeInputThread2, 1, holder);
        }

        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {
            Log.d(TAG, "surfaceDestroyed: surface2");
            if (decodeInputThread2 != null) {
                decodeInputThread2.interrupt();
            }
        }
    };

    private void consumeStream(DecodeInputThread decodeInputThread, int index, SurfaceHolder holder) {
        if (decodeInputThread == null) {
            decodeInputThread = new DecodeInputThread(holder, myImageReaders[index], streamConfigs.get(index).getResolution());
            decodeInputThread.start();
        }
    }

    private View.OnClickListener btnStartClick = new View.OnClickListener() {
        @Override
        public void onClick(View mView) {
            String resolution0 = dynamic0Resolution.getSelectedItem().toString();
            streamConfigs.get(0).setResolution(resolution0);
            String encodeBitrate0 = dynamic0EncodeBitrate.getSelectedItem().toString();
            streamConfigs.get(0).setEncodeBitrate(encodeBitrate0);
            String qpMin0 = dynamic0QualityParamMin.getSelectedItem().toString();
            streamConfigs.get(0).setQpMin(qpMin0);
            String qpMax0 = dynamic0QualityParamMax.getSelectedItem().toString();
            streamConfigs.get(0).setQpMax(qpMax0);
            String requestIFrame0 = dynamic0RequestIFrame.getSelectedItem().toString();
            streamConfigs.get(0).setRequestIFrame(requestIFrame0);
            String protocol0 = dynamic0Protocol.getSelectedItem().toString();
            streamConfigs.get(0).setProtocol(protocol0);
            String fps0 = dynamic0Fps.getSelectedItem().toString();
            streamConfigs.get(0).setFps(fps0);
            if (streamNumber > 1) {
                String resolution1 = dynamic1Resolution.getSelectedItem().toString();
                streamConfigs.get(1).setResolution(resolution1);
                String encodeBitrate1 = dynamic1EncodeBitrate.getSelectedItem().toString();
                streamConfigs.get(1).setEncodeBitrate(encodeBitrate1);
                String qpMin1 = dynamic1QualityParamMin.getSelectedItem().toString();
                streamConfigs.get(1).setQpMin(qpMin1);
                String qpMax1 = dynamic1QualityParamMax.getSelectedItem().toString();
                streamConfigs.get(1).setQpMax(qpMax1);
                String requestIFrame1 = dynamic1RequestIFrame.getSelectedItem().toString();
                streamConfigs.get(1).setRequestIFrame(requestIFrame1);
                String protocol1 = dynamic1Protocol.getSelectedItem().toString();
                streamConfigs.get(1).setProtocol(protocol1);
                String fps1 = dynamic1Fps.getSelectedItem().toString();
                streamConfigs.get(1).setFps(fps1);
            }
            if (streamNumber > 2) {
                String resolution2 = dynamic2Resolution.getSelectedItem().toString();
                streamConfigs.get(2).setResolution(resolution2);
                String encodeBitrate2 = dynamic2EncodeBitrate.getSelectedItem().toString();
                streamConfigs.get(2).setEncodeBitrate(encodeBitrate2);
                String qpMin2 = dynamic2QualityParamMin.getSelectedItem().toString();
                streamConfigs.get(2).setQpMin(qpMin2);
                String qpMax2 = dynamic2QualityParamMax.getSelectedItem().toString();
                streamConfigs.get(2).setQpMax(qpMax2);
                String requestIFrame2 = dynamic2RequestIFrame.getSelectedItem().toString();
                streamConfigs.get(2).setRequestIFrame(requestIFrame2);
                String protocol2 = dynamic2Protocol.getSelectedItem().toString();
                streamConfigs.get(2).setProtocol(protocol2);
                String fps2 = dynamic2Fps.getSelectedItem().toString();
                streamConfigs.get(2).setFps(fps2);
            }
            if (streamNumber > 3) {
                String resolution3 = dynamic3Resolution.getSelectedItem().toString();
                streamConfigs.get(3).setResolution(resolution3);
                String encodeBitrate3 = dynamic3EncodeBitrate.getSelectedItem().toString();
                streamConfigs.get(3).setEncodeBitrate(encodeBitrate3);
                String qpMin3 = dynamic3QualityParamMin.getSelectedItem().toString();
                streamConfigs.get(3).setQpMin(qpMin3);
                String qpMax3 = dynamic3QualityParamMax.getSelectedItem().toString();
                streamConfigs.get(3).setQpMax(qpMax3);
                String requestIFrame3 = dynamic3RequestIFrame.getSelectedItem().toString();
                streamConfigs.get(3).setRequestIFrame(requestIFrame3);
                String protocol3 = dynamic3Protocol.getSelectedItem().toString();
                streamConfigs.get(3).setProtocol(protocol3);
                String fps3 = dynamic3Fps.getSelectedItem().toString();
                streamConfigs.get(3).setFps(fps3);
            }

            if (mPreviewRequestBuilder != null) {
                setExTag(CaptureRequestEx.VIDEO_AUTO_STREAMRESOLUTION, MultiStreamTagUtil.constructResolutionTags(streamConfigs));
                setExTag(CaptureRequestEx.VIDEO_AUTO_ENCODEBITRATE, MultiStreamTagUtil.constructIntTags(streamConfigs, "getEncodeBitrate"));
                setExTag(CaptureRequestEx.VIDEO_AUTO_QUALITYPARAM, MultiStreamTagUtil.constructQPTags(streamConfigs));
                setExTag(CaptureRequestEx.VIDEO_AUTO_REQUESTIFRAME, MultiStreamTagUtil.constructByteTags(streamConfigs, "getRequestIFrame"));
                setExTag(CaptureRequestEx.DYNAMIC_FPS, MultiStreamTagUtil.constructByteTags(streamConfigs, "getFps"));
                setExTag(CaptureRequestEx.DYNAMIC_FORMAT, MultiStreamTagUtil.constructIntTags(streamConfigs, "getProtocol"));
                try {
                    mCaptureSession.setRepeatingRequest(mPreviewRequestBuilder.build(), mCaptureCallback, mBackgroundHandler);
                } catch (CameraAccessException e) {
                    Log.e(TAG, "onConfigured: setRepeatingRequest error!");
                    e.printStackTrace();
                }
            }
        }
    };

    private View.OnClickListener ptzTestClick = new View.OnClickListener() {
        @Override
        public void onClick(View mView) {
            int cx = 960;
            int cy = 540;
            int w = 1920 / 2;
            int h = 1080 / 2;
            Rect cropRegion1 = new Rect(cx, cy, w, h);
            int left =   cx - w/2;
            int right =  cx + w/2;
            int top =    cy - h/2;
            int bottom = cy + h/2;
            Rect cropRegion2 = new Rect(left, top, right, bottom);
            Rect cropRegion3 = new Rect(945, 531, 1949, 1096);
            try {
                mPreviewRequestBuilder.set(CaptureRequest.SCALER_CROP_REGION, cropRegion3); // 设置ptz参数
                mCaptureSession.setRepeatingRequest(mPreviewRequestBuilder.build(), null, mBackgroundHandler);
                saveRect = cropRegion3;

                Log.i(TAG, "ptzTest: Request. Rect(" + cropRegion3 + ")");

                CameraCharacteristics cameraCharacteristics = mCameraManager.getCameraCharacteristics(mCameraId);
                int type = (int) cameraCharacteristics.get(CameraCharacteristics.SCALER_CROPPING_TYPE); // 查询是否支持缩放
                float maxZoom = (float) cameraCharacteristics.get(CameraCharacteristics.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM); // 查询相机缩放范围
                Rect activeRect = (Rect) cameraCharacteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE); // 查询相机ptz范围
                Rect cropRect = mPreviewRequestBuilder.get(CaptureRequest.SCALER_CROP_REGION); // 查询相机当前ptz参数

                Log.i(TAG,"ptzTest: CameraCharacteristics.get! activeRect(" + activeRect + ") cropRect(" + cropRect + ") type(" + type + ") maxZoom("+ maxZoom + ")");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    };

    private int Tnum = 0;

    private View.OnClickListener tagTestClick = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Log.i(TAG,"tagTest enter.");

            try {
                CameraCharacteristics cameraCharacteristics = mCameraManager.getCameraCharacteristics(mCameraId);
                Rect activeRect = (Rect) cameraCharacteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE); // 查询相机ptz范围
                mPreviewRequestBuilder.set(CaptureRequest.SCALER_CROP_REGION, activeRect); // 设置ptz参数
                mCaptureSession.setRepeatingRequest(mPreviewRequestBuilder.build(), null, mBackgroundHandler);
                saveRect = activeRect;
            } catch (CameraAccessException e) {
                e.printStackTrace();
            }

////            final Integer[] value = {2, 0, 1000, 1, 1000};
//            final Byte[] value = {4,0,1,1,0,2,1,3,0};
//            try {
////                mPreviewRequestBuilder.set(CaptureRequestEx.MAX_STREAM_LEN, value);
//                mPreviewRequestBuilder.set(CaptureRequestEx.VIDEO_AUTO_REQUESTIFRAME, value);
//                mCaptureSession.setRepeatingRequest(mPreviewRequestBuilder.build(), mCaptureCallback, mBackgroundHandler);
//                Log.i(TAG,"tagTest finish.");
//            } catch (Exception e) {
//                e.printStackTrace();
//            }
        }
    };

    private void reConfigCaptureSession(List<Surface> surfaceList) {
        Log.i(TAG, "into reConfigCaptureSession");
        if (surfaceList.size() == 0) {
            Log.i(TAG, "reConfigCaptureSession invalid surfaceList size = 0");
            return;
        }
        if (mCaptureSession != null) {
            Log.e(TAG, "before abortCaptures");
            //mCaptureSession.abortCaptures();
            Log.e(TAG, "after abortCaptures");

            mCaptureSession.close();
            mCaptureSession = null;
        } else {
            Log.e(TAG, "mCaptureSession is null");
        }

        reCfgFlag = -1;
        try {
            mCameraDevice.createCaptureSession(surfaceList, new CameraCaptureSession.StateCallback() {
                @Override
                public void onConfigured(@NonNull CameraCaptureSession session) {
                    Log.i(TAG, "reConfigCaptureSession onConfigured: init  ");
                    mCaptureSession = session;
                    reCfgFlag = 1;
                }

                @Override
                public void onConfigureFailed(@NonNull CameraCaptureSession session) {
                    Log.i(TAG, "reConfigCaptureSession onConfigureFailed: 2");
                    reCfgFlag = 0;
                }
            }, mBackgroundHandler);
        } catch (CameraAccessException e) {
            reCfgFlag = 0;
            e.printStackTrace();
        }

        int waitTimes = 0;
        while (reCfgFlag == -1 && waitTimes++ < 500) {
            try {
                Log.i(TAG, "reConfigCaptureSession wait 1ms for session re-config");
                Thread.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        Log.i(TAG, "reConfigCaptureSession: " + ((reCfgFlag == 1) ? "success" : "failed"));
    }


    private View.OnClickListener previewClick = new View.OnClickListener() {
        @Override
        public void onClick(View mView) {
            if (previewRemoveFlag) {
                Log.i(TAG, "remove preview");
                mPreviewRequestBuilder.removeTarget(mSurfaceHolder.getSurface());
//                setExTag(CaptureRequestEx.ODM_META, constructTargetTags("remove", streamConfigs.size()));
//                outputSurfaceList.remove(outputSurfaceList.get(outputSurfaceList.size() -1));
                outputSurfaceList.remove(mSurfaceHolder.getSurface());
                reConfigCaptureSession(outputSurfaceList);
                previewRemoveFlag = false;
                previewButton.setText("Add Preview");
            } else {
                Log.i(TAG, "add preview");
                mPreviewRequestBuilder.addTarget(mSurfaceHolder.getSurface());
//                setExTag(CaptureRequestEx.ODM_META, constructTargetTags("add", streamConfigs.size()));
//                outputSurfaceList.add(mSurfaceHolder.getSurface());
                outputSurfaceList.add(mSurfaceHolder.getSurface());
                reConfigCaptureSession(outputSurfaceList);
                previewRemoveFlag = true;
                previewButton.setText("Remove Preview");
            }

            try {
                mCaptureSession.setRepeatingRequest(mPreviewRequestBuilder.build(), mCaptureCallback, mBackgroundHandler);
            } catch (CameraAccessException e) {
                e.printStackTrace();
            }
        }
    };

    private View.OnClickListener stream0Click = new View.OnClickListener() {
        @Override
        public void onClick(View mView) {
            if (stream0RemoveFlag) {
                Log.i(TAG, "remove stream0");
                mPreviewRequestBuilder.removeTarget(imageReaders[0].getSurface());
//                setExTag(CaptureRequestEx.ODM_META, constructTargetTags("remove", 0));
//                outputSurfaceList.remove(outputSurfaceList.get(0));
                outputSurfaceList.remove(imageReaders[0].getSurface());
                reConfigCaptureSession(outputSurfaceList);
                stream0RemoveFlag = false;
                stream0Button.setText("Add stream0");
            } else {
                Log.i(TAG, "add stream0");
                mPreviewRequestBuilder.addTarget(imageReaders[0].getSurface());
//                setExTag(CaptureRequestEx.ODM_META, constructTargetTags("add", 0));
//                outputSurfaceList.add(0, imageReaders[0].getSurface());
                outputSurfaceList.add(imageReaders[0].getSurface());
                reConfigCaptureSession(outputSurfaceList);
                stream0RemoveFlag = true;
                stream0Button.setText("Remove stream0");
            }

            try {
                mCaptureSession.setRepeatingRequest(mPreviewRequestBuilder.build(), mCaptureCallback, mBackgroundHandler);
            } catch (CameraAccessException e) {
                e.printStackTrace();
            }
        }
    };

    private View.OnClickListener stream1Click = new View.OnClickListener() {
        @Override
        public void onClick(View mView) {
            if (stream1RemoveFlag) {
                Log.i(TAG, "remove stream1");
                mPreviewRequestBuilder.removeTarget(imageReaders[1].getSurface());
//                setExTag(CaptureRequestEx.ODM_META, constructTargetTags("remove", 1));
//                outputSurfaceList.remove(outputSurfaceList.get(1));
                outputSurfaceList.remove(imageReaders[1].getSurface());
                reConfigCaptureSession(outputSurfaceList);
                stream1RemoveFlag = false;
                stream1Button.setText("Add stream1");
            } else {
                Log.i(TAG, "add stream1");
                mPreviewRequestBuilder.addTarget(imageReaders[1].getSurface());
//                setExTag(CaptureRequestEx.ODM_META, constructTargetTags("add", 1));
//                outputSurfaceList.add(1, imageReaders[1].getSurface());
                outputSurfaceList.add(imageReaders[1].getSurface());
                reConfigCaptureSession(outputSurfaceList);
                stream1RemoveFlag = true;
                stream1Button.setText("Remove stream1");
            }

            try {
                mCaptureSession.setRepeatingRequest(mPreviewRequestBuilder.build(), mCaptureCallback, mBackgroundHandler);
            } catch (CameraAccessException e) {
                e.printStackTrace();
            }
        }
    };

    private View.OnClickListener stream2Click = new View.OnClickListener() {
        @Override
        public void onClick(View mView) {
            if (stream2RemoveFlag) {
                Log.i(TAG, "remove stream2");
                mPreviewRequestBuilder.removeTarget(imageReaders[2].getSurface());
//                setExTag(CaptureRequestEx.ODM_META, constructTargetTags("remove", 2));
                outputSurfaceList.remove(imageReaders[2].getSurface());
                reConfigCaptureSession(outputSurfaceList);
                stream2RemoveFlag = false;
                stream2Button.setText("Add stream2");
            } else {
                Log.i(TAG, "add stream2");
                mPreviewRequestBuilder.addTarget(imageReaders[2].getSurface());
//                setExTag(CaptureRequestEx.ODM_META, constructTargetTags("add", 2));
                outputSurfaceList.add(imageReaders[2].getSurface());
                reConfigCaptureSession(outputSurfaceList);
                stream2RemoveFlag = true;
                stream2Button.setText("Remove stream2");
            }

            try {
                mCaptureSession.setRepeatingRequest(mPreviewRequestBuilder.build(), mCaptureCallback, mBackgroundHandler);
            } catch (CameraAccessException e) {
                e.printStackTrace();
            }
        }
    };

    private View.OnClickListener stream3Click = new View.OnClickListener() {
        @Override
        public void onClick(View mView) {
            if (stream3RemoveFlag) {
                Log.i(TAG, "remove stream3");
                mPreviewRequestBuilder.removeTarget(imageReaders[3].getSurface());
//                setExTag(CaptureRequestEx.ODM_META, constructTargetTags("remove", 3));
                outputSurfaceList.remove(imageReaders[3].getSurface());
                reConfigCaptureSession(outputSurfaceList);
                stream3RemoveFlag = false;
                stream3Button.setText("Add stream3");
            } else {
                Log.i(TAG, "add stream3");
                mPreviewRequestBuilder.addTarget(imageReaders[3].getSurface());
//                setExTag(CaptureRequestEx.ODM_META, constructTargetTags("add", 3));
                outputSurfaceList.add(imageReaders[3].getSurface());
                reConfigCaptureSession(outputSurfaceList);
                stream3RemoveFlag = true;
                stream3Button.setText("Remove stream3");
            }

            try {
                mCaptureSession.setRepeatingRequest(mPreviewRequestBuilder.build(), mCaptureCallback, mBackgroundHandler);
            } catch (CameraAccessException e) {
                e.printStackTrace();
            }
        }
    };
}

